﻿using ClientAppraise.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using Wpf.Ui.Controls;

namespace ClientAppraise.ViewModels.Validator
{
    public class MyObservableValidator : ObservableValidator
    {
        public FrameworkElement? Framework { get; set; }
        public Boolean IsOddity { get; private set; }

        List<BindingExpression> Be { get; set; } = new List<BindingExpression>();

        public Dictionary<string, List<string>> ServerErrors = [];

        public bool HasServerErrors => this.ServerErrors.Count > 0;

        protected new void ClearErrors(string? propertyName = null)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.Invoke(new Action(() => ClearErrors(propertyName)));
                return;
            }

            if (ServerErrors != default)
            {
                this.ServerErrors.Clear();
            }

            base.ClearErrors(propertyName);

            ClearErrElement(propertyName);
        }


        protected void ValidateAllProperties(bool isOddity = true)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.Invoke(new Action(() => ValidateAllProperties(isOddity)));
                return;
            }

            this.IsOddity = isOddity;
            if (IsOddity)
                this.ErrorsChanged -= MyObservableValidator_ErrorsChanged;

            ClearErrElement();

            base.ClearErrors();
            if (IsOddity)
                this.ErrorsChanged += MyObservableValidator_ErrorsChanged;
            base.ValidateAllProperties();

        }
        protected void ValidateAllPropertiesWithServer(Dictionary<string, List<string>> serverErrors)
        {
            this.ServerErrors = serverErrors;
            ValidateAllPropertiesWithServer();
        }
        protected void ValidateAllPropertiesWithServer(bool isOddity = true)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.Invoke(new Action(() => ValidateAllPropertiesWithServer(isOddity)));
                return;
            }

            this.IsOddity = isOddity;
            if (IsOddity)
                this.ErrorsChanged -= MyObservableValidator_ErrorsChanged;

            ClearErrElement();

            base.ClearErrors();
            if (IsOddity)
                this.ErrorsChanged += MyObservableValidator_ErrorsChanged;
            base.ValidateAllProperties();
        }

        private void MyObservableValidator_ErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
        {
            if (Framework == default) return;

            GetControls();

            var be = Be.FirstOrDefault(t => t.ResolvedSourcePropertyName == e.PropertyName);
            if (be != default)
                ShowErrElement(be);
        }

        private void ShowServerError()
        {
            foreach (var se in ServerErrors)
            {
                var be = Be.FirstOrDefault(t => t.ResolvedSourcePropertyName == se.Key);
                if (be != default)
                    ShowErrElement(be, se.Value[0]);
            }
        }


        private void ShowErrElement(BindingExpression be, string errmsg = "")
        {
            var control = be.Target;

            void genErrElement(FrameworkElement ele)
            {
                var pEle = (Panel)VisualTreeHelper.GetParent(control);

                if (AnySonElement(pEle, be.ResolvedSourcePropertyName + "_err"))
                {
                    return;//如果有报告了，这里就不再提示了
                }

                var errEle = new ZxErrCard
                {
                    Name = be.ResolvedSourcePropertyName + "_err"
                };

                if (string.IsNullOrEmpty(errmsg))
                {
                    errEle.Content = be.ValidationErrors[0].ErrorContent;
                }
                else
                {
                    errEle.Content = errmsg;
                }

                var index = pEle.Children.IndexOf(ele);

                pEle.Children.Insert(index, errEle);
            }

            while (true)
            {
                var a = VisualTreeHelper.GetParent(control);

                if (a == default) break;

                control = a;

                if (a is CardControl || a is CardExpander || a is ZxCard)
                {
                    genErrElement((FrameworkElement)a);
                    break;
                }

            }

        }

        private bool AnySonElement(Panel p, string name)
        {
            foreach (FrameworkElement item in p.Children)
            {

                if (item.Name == name)
                {
                    return true;
                }
            }
            return false;
        }

        private void ClearErrElement(string? propertyName = null)
        {
            if (Framework == default) return;
            void fun(DependencyObject fw, string? errEle)
            {
                if (fw == default) return;

                var count = VisualTreeHelper.GetChildrenCount(fw);

                for (int i = 0; i < count; i++)
                {
                    var elem = VisualTreeHelper.GetChild(fw, i);

                    if (elem is ZxErrCard errCard)
                    {
                        if (string.IsNullOrEmpty(errEle))
                        {
                            count--;
                            (fw as Panel)?.Children.Remove((UIElement)elem);
                        }
                        else if (errCard.Name == errEle)
                        {
                            (fw as Panel)?.Children.Remove((UIElement)elem);
                            break;
                        }
                    }
                    else
                    {
                        fun(elem, errEle);
                    }
                }
            }

            string? aasdfsa = propertyName == default ? propertyName : propertyName + "_err";

            fun(this.Framework, aasdfsa);
        }

        private void GetControls()
        {
            if (Be.Count > 0) return;

            //取得所有属性
            List<String> pro = [];
            pro = this.GetType().GetProperties().Where(t => t.GetCustomAttributes<ValidationAttribute>().Any()).Select(t => t.Name).ToList();


            if (Framework == default) return;

            void fun(DependencyObject fw)
            {
                var count = VisualTreeHelper.GetChildrenCount(fw);

                for (int i = 0; i < count; i++)
                {
                    var elem = VisualTreeHelper.GetChild(fw, i);

                    if (elem is System.Windows.Controls.TextBox textBox)
                    {
                        var myBinding = BindingOperations.GetBindingExpression(textBox, System.Windows.Controls.TextBox.TextProperty);

                        if (myBinding != default && pro.Contains(myBinding.ResolvedSourcePropertyName))
                        {
                            Be.Add(myBinding);
                        }
                    }
                    else
                    {
                        fun(elem);
                    }
                }
            }

            fun(this.Framework);
        }

    }
}
